﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;

namespace Shared.Method
{
    public class PingBaseClass
    {
        private const int SOCKET_ERROR = -1;
        private const int ICMP_ECHO = 8;
        /// <summary>
        /// 在1月10日前改造成ICMP PING命令
        /// </summary>
        /// <param name="ipAddr"></param>
        /// <returns></returns>
        public static bool PingTest(string ipAddr)
        {
            try
            {
                Ping pingSend = new Ping();
                PingOptions options = new PingOptions();
                options.DontFragment = true;
                string data = "TEST";
                var buffer = Encoding.UTF8.GetBytes(data);
                PingReply reply = pingSend.Send(ipAddr, 1000, buffer);
                if (reply.Status == IPStatus.Success)
                    return true;
                else
                    return false;
            }
            catch
            {
                return false;
            }
        }

        public static bool PingTest(string localIp,string destIp)
        {
            try
            {
                EndPoint serverEP = new IPEndPoint(IPAddress.Parse(destIp.Trim()), 0);
                EndPoint localEP = new IPEndPoint(IPAddress.Parse(localIp.Trim()), 0);


                //初始化SOCKET
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
                socket.Bind(localEP);//与本地终节点绑定

                //定义一个多字节的数据,COPY的一个PING包
                byte[] sendBuf = { 0x08,0x00,0x4d,0x57,0x00,0x01,0x00,0x04,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
                ,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69};

                int nBytes = 0;
                if ((nBytes = socket.SendTo(sendBuf, sendBuf.Length, 0, serverEP)) == SOCKET_ERROR)
                {
                    socket.Close();
                    return false;
                }

                byte[] recBuf = new byte[256];


                nBytes = socket.ReceiveFrom(recBuf, 256, 0, ref serverEP);
                if (nBytes == SOCKET_ERROR || nBytes == 0)
                {
                    socket.Close();
                    return false;
                }
                else
                {
                    socket.Close();
                    return true;
                }
            }
            catch (Exception)
            {
                //LogHelper.WriteErrLogTxt("ping Test", "ping error", ex.ToString());
                return false;
            }
        }

        /// <summary> 
        ///  This method get the Packet and calculates the total size 
        ///  of the Pack by converting it to byte array 
        /// </summary> 
        public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer, Int32 PacketSize, Int32 PingData)
        {
            Int32 cbReturn = 0;
            // serialize the struct into the array 
            int Index = 0;

            Byte[] b_type = new Byte[1];
            b_type[0] = (packet.Type);

            Byte[] b_code = new Byte[1];
            b_code[0] = (packet.SubCode);

            Byte[] b_cksum = BitConverter.GetBytes(packet.CheckSum);
            Byte[] b_id = BitConverter.GetBytes(packet.Identifier);
            Byte[] b_seq = BitConverter.GetBytes(packet.SequenceNumber);

            Array.Copy(b_type, 0, Buffer, Index, b_type.Length);
            Index += b_type.Length;

            Array.Copy(b_code, 0, Buffer, Index, b_code.Length);
            Index += b_code.Length;

            Array.Copy(b_cksum, 0, Buffer, Index, b_cksum.Length);
            Index += b_cksum.Length;

            Array.Copy(b_id, 0, Buffer, Index, b_id.Length);
            Index += b_id.Length;

            Array.Copy(b_seq, 0, Buffer, Index, b_seq.Length);
            Index += b_seq.Length;

            // copy the data 
            Array.Copy(packet.Data, 0, Buffer, Index, PingData);
            Index += PingData;
            if (Index != PacketSize/* sizeof(IcmpPacket)  */)
            {
                cbReturn = -1;
                return cbReturn;
            }

            cbReturn = Index;
            return cbReturn;
        }
        /// <summary> 
        ///  This Method has the algorithm to make a checksum 
        /// </summary> 
        public static UInt16 checksum(UInt16[] buffer, int size)
        {
            Int32 cksum = 0;
            int counter;
            counter = 0;

            while (size > 0)
            {
                UInt16 val = buffer[counter];

                cksum += buffer[counter];
                counter += 1;
                size -= 1;
            }

            cksum = (cksum >> 16) + (cksum & 0xffff);
            cksum += (cksum >> 16);
            return (ushort)(~cksum);
        }
    }



    /// 类结束 
    /// <summary> 
    ///  Class that holds the Pack information 
    /// </summary> 
    public class IcmpPacket
    {
        public Byte Type { get; set; }    // type of message 
        public Byte SubCode { get; set; }   // type of sub code 
        public UInt16 CheckSum { get; set; }    // ones complement checksum of struct 
        public UInt16 Identifier { get; set; }       // identifier 
        public UInt16 SequenceNumber { get; set; }      // sequence number 
        public Byte[] Data { get; set; }

    } // class IcmpPacket 

}
